﻿/**
* CRL
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CRL.Core;
using CRL.Core.Extension;
using CRL.Core.Remoting.WorkConsole;
using Quartz;
using Quartz.Impl;
using Quartz.Spi;
using TaskStatus = CRL.Core.Remoting.WorkConsole.TaskStatus;

namespace CRL.QuartzScheduler
{
    /// <summary>
    /// QuartzWorker自动任务
    /// </summary>
	public class QuartzWorker
	{
        //https://www.quartz-scheduler.net/documentation/quartz-3.x/quick-start.html
        IScheduler scheduler;
        internal IWorkManageClient taskManage;
        internal static QuartzWorker instance;
        string jobGroup = "defaultGroup";
        string triggerPrex = "Trigger";
        string jobNamePrex = "Job";
        public QuartzWorker(IWorkManageClient _taskManage = null)
        {
            // 创建一个工作调度器工场
            ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
            // 获取一个任务调度器
            scheduler = schedulerFactory.GetScheduler().Result;
            taskManage = _taskManage;
            instance = this;
            if (taskManage != null)
            {
                taskManage.OnPauseWork = (workName) =>
                {
                    var triggerName = $"{triggerPrex}_{workName}";
                    scheduler.PauseTrigger(new TriggerKey(triggerName, jobGroup));
                    Console.WriteLine($"{DateTime.Now} {workName} pause");
                    taskManage.UpdateWorkStatus(workName, WorkStatus.Pause);
                };
                taskManage.OnResumeWork = (workName) =>
                {
                    var triggerName = $"{triggerPrex}_{workName}";
                    scheduler.ResumeTrigger(new TriggerKey(triggerName, jobGroup));
                    Console.WriteLine($"{DateTime.Now} {workName} resume");
                    taskManage.UpdateWorkStatus(workName, WorkStatus.Runing);
                };
                taskManage.StartMonitor();
            }
        }
        //public static Dictionary<JobKey, bool> workCache = new Dictionary<JobKey, bool>();

#if NETSTANDARD
        public void SetJobFactory(IServiceProvider serviceProvider)
        {
            scheduler.JobFactory = new QuartzFactory(serviceProvider);
        }
#endif
        /// <summary>
        /// 添加一个任务
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="work"></param>
        public void AddWork<T>(T work, string name = "") where T : QuartzJob
        {
            AddWorkBase<T>(new TriggerData()
            {
                CronExpression = work.CronExpression,
                RepeatCount = work.RepeatCount,
                RepeatInterval = work.RepeatInterval,
                TagData = work.TagData
            }, name);
        }

        public void AddWorkBase<T>(TriggerData triggerData, string name = "") where T : QuartzJob
        {
            Type type = typeof(T);
            var jobName = $"{jobNamePrex}_{type}_{name}";
            var triggerName = $"{triggerPrex}_{jobName}";
            var dic = new JobDataMap();
            dic.Add("TagData", triggerData.TagData);
            dic.Add("CustomFunc", triggerData.CustomFunc);
            IJobDetail job = JobBuilder.Create<T>().WithIdentity(jobName, jobGroup).SetJobData(dic).Build();

            // Trigger the job to run now, and then repeat every 10 seconds
            var build = TriggerBuilder.Create()
                .WithIdentity(triggerName, jobGroup)
                .StartNow();

            if (!string.IsNullOrEmpty(triggerData.CronExpression))
            {
                build.WithCronSchedule(triggerData.CronExpression);
            }
            else
            {
                build.WithSimpleSchedule(x => x
                    .WithInterval(triggerData.RepeatInterval)
                    .RepeatForever());
            }
            var trigger = build.Build();

            scheduler.ScheduleJob(job, trigger);
            //workCache.Remove(job.Key);
            //workCache.Add(job.Key, false);
            var work = new WorkDetail
            {
                WorkName = jobName,
                Repeat = string.IsNullOrEmpty(triggerData.CronExpression) ? triggerData.RepeatInterval.ToString() : triggerData.CronExpression,
                WorkStatus = WorkStatus.Runing,
                TaskStatus = TaskStatus.Wait,
                Args = triggerData.TagData?.ToJson(),
                HeartTime = DateTime.Now
            };
            taskManage?.InitWork(work);
        }

        public void AddCustomWork(Action<object> func, TriggerData triggerData, string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentException(nameof(name));
            }
            triggerData.CustomFunc = func;
            AddWorkBase<_CustomWork>(triggerData, name);
        }
        public void RemoveWork<T>(string name = "") where T : QuartzJob
        {
            var type = typeof(T);
            var jobName = $"{jobNamePrex}_{type}_{name}";
            scheduler.UnscheduleJob(new TriggerKey(jobName, jobGroup));
            scheduler.DeleteJob(new JobKey(jobName, jobGroup));
            taskManage?.RemoveWork(jobName);
        }
        public void RemoveCustomWork(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentException(nameof(name));
            }
            RemoveWork<_CustomWork>(name);
        }
        /// <summary>
        /// 开始运行
        /// </summary>
        public void Start()
		{
			scheduler.Start();
            EventLog.Log(GetType() + "已启动");
		}
		/// <summary>
		/// 停止运行
		/// </summary>
		public void Stop()
        {
            scheduler.Shutdown(false);
            try
            {
                scheduler.Clear();
            }
            catch { }
            //workCache.Clear();
            EventLog.Log(GetType() + "已停止");
		}
	}
}
